#ifndef LIST_H
#define	LIST_H

#include <iostream>

#include "utils.h"

struct EmptyList
{
};

template<int value, typename Tail>
struct List
{
   static const int data = value;
   typedef Tail tail;
};

template<typename List>
struct Length
{
   static const int length = 1 + Length<typename List::tail>::length;
};

template<>
struct Length<EmptyList>
{
   static const int length = 0;
};

template<int count, typename list>
struct Prefix
{
   typedef List<list::data, typename Prefix<count - 1,
           typename list::tail>::result > result;
};

template<typename List>
struct Prefix<0, List>
{
   typedef EmptyList result;
};

template<int count, typename list>
struct Suffix
{
   typedef typename Suffix<count - 1, typename list::tail>::result result;
};

template<typename list>
struct Suffix<0, list>
{
   typedef list result;
};

template<typename list, int value>
struct Append
{
   typedef List<list::data,
           typename Append<typename list::tail, value>::result > result;
};

template<int value>
struct Append<EmptyList, value>
{
   typedef List<value, EmptyList> result;
};

template<typename list>
struct Reverse
{
   typedef typename Append<typename Reverse<typename list::tail>::result,
           list::data>::result result;
};

template<>
struct Reverse<EmptyList>
{
   typedef EmptyList result;
};

template<typename list, int count>
struct Shift
{
   typedef List<0, typename Shift<list, count - 1>::result > result;
};

template<typename list>
struct Shift<list, 0>
{
   typedef list result;
};

template<typename list>
struct CutZeroes
{
   typedef typename MetaIf<list::data == 0,
           typename CutZeroes<typename list::tail>::result,
           list>::result result;
};

template<>
struct CutZeroes<EmptyList>
{
   typedef EmptyList result;
};

template<typename List>
void print()
{
   std::cout << List::data;
   print<typename List::tail>();
}

template<>
void print<EmptyList>()
{
}

#endif